﻿#region Using Statements

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

#endregion


namespace Freeform
{

    #region Component

    /// <summary>
    /// Basically every class in the engine extends from Component. Each component carries a unique ID so that they can be referenced
    /// remotely via network messages or so that closed loop references can be maintained when a game is serialized to persistant storage.
    /// </summary>
    public class Component
    {

        #region Members

        /// <summary>
        /// Gets the ID of this component.
        /// </summary>
        public virtual UInt64 ComponentID { get; private set; }


        /// <summary>
        /// Gets the next ID to be issued.
        /// </summary>
        internal static UInt64 NextID { get; set; }


        /// <summary>
        /// Gets a reference to the game that this component belongs to.
        /// </summary>
        public virtual Game Game { get; private set; }


        /// <summary>
        /// Gets whether or not this entity has been disposed.
        /// </summary>
        public virtual Boolean Disposed { get; private set; }


        /// <summary>
        /// Gets or sets whether or not the component is currently loaded.
        /// </summary>
        public virtual Boolean IsLoaded { get; set; }


        /// <summary>
        /// Gets or sets whether this entity is currently enabled (receives updates.)
        /// </summary>
        public virtual Boolean IsEnabled { get; set; }


        /// <summary>
        /// Gets or sets the priority of the component, which affects its update order in the component lists if Priority sorting is enabled.
        /// </summary>
        public virtual Single Priority { get; set; }


        /// <summary>
        /// Gets the list that this component belongs to.
        /// </summary>
        public virtual ComponentList List { get; private set; }

        #endregion


        #region Init

        /// <summary>
        /// Creates a new component for the game.
        /// </summary>
        /// <param name="game">The game.</param>
        public Component(ComponentList list)
        {
            List = list;
            Game = List.Game;
            ComponentID = NextID++;
            IsEnabled = true;
            IsLoaded = true;
            Game.FreeformComponents.Add(ComponentID, this);
            List.Library.Add(ComponentID, this);
        }

        #endregion


        #region Update

        /// <summary>
        /// Allows the component to update itself.
        /// </summary>
        /// <param name="time">Provides a snapshot of timing values.</param>
        public virtual void Update(GameTime time)
        {

        }

        #endregion


        #region Dispose

        /// <summary>
        /// Disposes the entity and removes it from the world.
        /// </summary>
        public void Dispose()
        {
            if (!Disposed)
                OnDispose();
        }


        /// <summary>
        /// Actions to carry out upon disposal.
        /// </summary>
        protected virtual void OnDispose() 
        {
            Game.FreeformComponents.Remove(ComponentID);
            List.Library.Remove(ComponentID);
            Disposed = true;
        }

        #endregion

    }

    #endregion


    #region ComponentList

    /// <summary>
    /// An component list is a datastructure used to access a list of components.
    /// </summary>
    public class ComponentList
    {

        #region Members

        /// <summary>
        /// Gets or sets the underlying data structure used by the entity list.
        /// </summary>
        internal Dictionary<UInt64, Component> Library { get; set; }


        /// <summary>
        /// Gets a list of all entities in the list.
        /// </summary>
        public List<Component> All { get; private set; }


        /// <summary>
        /// Gets a list of all loaded entities in the list.
        /// </summary>
        public List<Component> Loaded { get; private set; }


        /// <summary>
        /// Gets a list of all unloaded entities in the list.
        /// </summary>
        public List<Component> Unloaded { get; private set; }


        /// <summary>
        /// Gets a list of all entities that use active collision settings.
        /// </summary>
        public List<Entity> ActiveColliders { get; private set; }


        /// <summary>
        /// Gets a list of all entities that use passive collision settings.
        /// </summary>
        public List<Entity> PassiveColliders { get; private set; }


        /// <summary>
        /// Gets or sets whether the elements of the list should be sorted based on priority.
        /// </summary>
        public Boolean PrioritySorting { get; set; }


        /// <summary>
        /// Gets a reference to the game that this ComponentList belongs to.
        /// </summary>
        public Game Game { get; private set; }

        #endregion


        #region Init

        /// <summary>
        /// Creates a new entity list.
        /// </summary>
        public ComponentList(Game game)
        {
            Game = game;
            Library = new Dictionary<UInt64, Component>();
            All = new List<Component>();
            Loaded = new List<Component>();
            Unloaded = new List<Component>();
            ActiveColliders = new List<Entity>();
            PassiveColliders = new List<Entity>();
        }

        #endregion


        #region Update

        /// <summary>
        /// Updates all the entity lists from the underlying data structure.
        /// </summary>
        public virtual void UpdateLists()
        {
            // Load all entities into the All list.
            All = Library.Values.ToList();

            // Clear all other lists.
            Loaded.Clear();
            Unloaded.Clear();
            ActiveColliders.Clear();
            PassiveColliders.Clear();

            // Sort list if necessary.
            if (PrioritySorting)
                All.Sort(ComparePriority);

            // Setup other lists.
            for (int i = 0; i < All.Count; i++)
            {
                if (All[i].IsLoaded)
                {
                    Loaded.Add(All[i]);

                    Entity Entity = All[i] as Entity;
                    if (Entity != null)
                    {
                        if (Entity.CollisionProperties.CollisionType == CollisionType.Active)
                            ActiveColliders.Add(Entity);
                        else if (Entity.CollisionProperties.CollisionType == CollisionType.Passive)
                            PassiveColliders.Add(Entity);
                    }
                }
                else
                    Unloaded.Add(All[i]);
            }
        }

        #endregion


        #region Utility

        /// <summary>
        /// This function is the comparer used to sort the components via their priority.
        /// </summary>
        /// <param name="a">Component A.</param>
        /// <param name="b">Component B.</param>
        /// <returns></returns>
        private Int32 ComparePriority(Component a, Component b)
        {
            if (a.Priority == b.Priority) return 0;
            if (a.Priority > b.Priority) return 1;
            return -1;
        }

        #endregion

    }

    #endregion

}
